﻿#define _CRT_SECURE_NO_WARNINGS 1
//#include<stdio.h>
//
//int main()
//{
//	printf("hello world\n");
//
//	return 0;
//}

//#include<iostream>
//using namespace std;
//
//int main()
//{
//	cout << "hello world！！！\n" << endl;
//	return 0;
//}

//namespace zzy
//{
//	// 命名空间中可以定义变量/函数/类型
//	int rand = 10;
//
//	int Add(int left, int right)
//	{
//		return left + right;
//	}
//
//	struct Node
//	{
//		struct Node* next;
//		int val;
//	};
//}

//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//
//int x = 0;
//
//namespace zzy
//{
//	int x = 1;
//}
//
//void func()
//{
//	int x = 2;//局部域只能在当前局部访问
//}
//
//int main()
//{
//	int x = 3;
//
//	printf("%d\n", x);//访问当前局部域
//	printf("%d\n", zzy::x);//访问命名空间域
//	printf("%d\n", ::x);//访问全局域
//
//	return 0;
//}

//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//
//namespace bit
//{
//	// zzy
//	namespace zzy
//	{
//		int rand = 1;
//		int Add(int left, int right)
//		{
//			return left + right;
//		}
//	}
//	// byb
//	namespace byb
//	{
//		int rand = 2;
//		int Add(int left, int right)
//		{
//			return (left + right) * 10;
//		}
//	}
//}
//int main()
//{
//	printf("%d\n", bit::zzy::rand);
//	printf("%d\n", bit::byb::rand);
//	printf("%d\n", bit::zzy::Add(1, 2));
//	printf("%d\n", bit::byb::Add(1, 2));
//	return 0;
//}

//#include<stdio.h>
//namespace zzy
//{
//	int a = 0;
//	int b = 1;
//}
//// 指定命名空间访问
//int main()
//{
//	printf("%d\n", N::a);
//	return 0;
//}

//#include<stdio.h>
//namespace zzy
//{
//	int a = 0;
//	int b = 1;
//}
//// using将命名空间中某个成员展开
//using N::b;
//int main()
//{
//	printf("%d\n", N::a);
//	printf("%d\n", b);
//	return 0;
//}

//#include<iostream>
//namespace zzy
//{
//	int a = 0;
//	int b = 1;
//}
//
//// 展开命名空间中全部成员
//using namespace zzy;
//int main()
//{
//	printf("%d\n", a);
//	printf("%d\n", b);
//	return 0;
//}

//#include <iostream>
//using namespace std;
//int main()
//{
//	int a = 0;
//	double b = 0.1;
//	char c = 'x';
//
//	cout << a << " " << b << "  " << c << endl;
//	std::cout << a << " " << b << "  " << c << std::endl;
//	scanf("%d%lf", &a, &b);
//	printf("%d %lf\n", a, b);
//	// 可以⾃动识别变量的类型
//	cin >> a;
//	cin >> b >> c;
//	cout << a << endl;
//	cout << b << "  " << c << endl;
//	return 0;
//}

//#include <iostream>
//#include <assert.h>
//using namespace std;
//void Func(int a = 0)
//{
//	cout << a << endl;
//}
//int main()
//{
//	Func();
//	// 没有传参时，使⽤参数的默认值
//
//		Func(10);   // 传参时，使⽤指定的实参
//
//		return 0;
//}

//#include <iostream>
//using namespace std;
//// 全缺省
//
//void Func1(int a = 10, int b = 20, int c = 30)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl << endl;
//}
//// 半缺省
//
//void Func2(int a, int b = 10, int c = 20)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl << endl;
//}
//int main()
//{
//	Func1();
//	Func1(1);
//	Func1(1, 2);
//	Func1(1, 2, 3);
//	Func2(100);
//	Func2(100, 200);
//	Func2(100, 200, 300);
//	return 0;
//}
//
//#include<iostream>
//using namespace std;
//
//// 1、参数类型不同
//// 
////int Add(int left, int right)
////{
////	cout << "int Add(int left, int right)" << endl;
////	return left + right;
////}
////double Add(double left, double right)
////{
////	cout << "double Add(double left, double right)" << endl;
////	return left + right;
////}
//
//// 2、参数个数不同
//
////void f()
////{
////	cout << "f()" << endl;
////}
////void f(int a,int b)
////{
////	cout << "f(int a,int b)" << endl;
////}
//
//// 3、参数类型顺序不同
//
//void f(int a, char b)
//{
//	cout << "f(int a,char b)" << endl;
//}
//
//void f(char b, int a)
//{
//	cout << "f(char b, int a)" << endl;
//}
//
//int main()
//{
//	/*Add(10, 20);
//	Add(10.1, 20.2);*/
//
//	//f();
//	//f(10, 20);
//
//	f(10, 'a');
//	f('a', 10);
//	return 0;
//}


//#include<iostream>
//using namespace std;
//// 返回值不同不能作为重载条件，因为调⽤时也⽆法区分
//
////void fxx()
//// {}
//// 
//// int fxx()
//// {
////         
////	return 0;
//// }
//
//// 下面两个函数构成重载
//// f()但是调用时，会报错，存在歧义，编译器不知道调用谁
//void f1()
//{
//	cout << "f()" << endl;
//}
//
//void f1(int a = 10)
//{
//	cout << "f(int a)" << endl;
//}
//
// int main()
// {
//	 /*fxx();*/
//	 f1(10);
//	 return 0;
// }

//
//#include<iostream>
//using namespace std;
//int main()
//{
//	int a = 10;
//	// 编译报错：“ra” :必须初始化引⽤
//    //int& ra;
//	int& b = a;
//	int c = 20;
//	b = c;
//	// 这⾥并⾮让b引⽤c，因为C++引⽤不能改变指向，
//	// 这⾥是⼀个赋值
//
//		cout << &a << endl;
//	cout << &b << endl;
//	cout << &c << endl;
//	return 0;
//}

//#include <iostream>
//
//int main() {
//    int num1 = 10;
//    int num2 = 20;
//
//    // 定义引用并初始化为引用num1
//    int& ref = num1;
//
//    // 尝试让ref引用num2
//    ref = num2;
//
//    return 0;
//}
//
//#include<iostream>
//using namespace std;
//
//int main()
//{
//	int a = 0;
//	int& b = a;
//	int& c = a;
//	// 也可以给别名b取别名，d相当于还是a的别名
//	int& d = b;
//	++d;
//
//	// 这里取地址我们看到是一样的
//	cout << &a << endl;
//	cout << &b << endl;
//	cout << &c << endl;
//	cout << &d << endl;
//
//	return 0;
//}

//#include <iostream>
//
//int main() {
//    // 定义一个整数变量a
//    int a = 10;
//
//    // 定义引用b，让它引用a，此时b就是a的别名
//    int& b = a;
//
//    // 对a进行操作，等同于对b进行操作，因为它们指向同一个内存地址
//    a = 20;
//
//    std::cout << "a的值为：" << a << std::endl;
//    std::cout << "b的值为" << b << std::endl;
//
//    return 0;
//}

//#include<iostream>
//using namespace std;
//struct A
//{
//    int arr[1000];
//};
//
//void func(A& aa)
//{
//
//}
//
//int main()
//{
//    A aa1;
//    func(aa1);//传指针的话我们就直接传过去指针的4个字节
//    //如果将这个结构体传过去的话，那么就是4000个字节，我们需要额外进行拷贝的操作
//    //我们在这里使用引用的话，更方便些，同样和指针一样不需要进行额外的拷贝的操作
//    return 0;
//}


//#include<iostream>
//using namespace std;
//
//void Swap(int& rx, int& ry)
//{
//	int tmp = rx;
//	rx = ry;
//	ry = tmp;
//}
//int main()
//{
//	int x = 0, y = 1;
//	cout << x << " " << y << endl;
//	Swap(x, y);
//	cout << x << " " << y << endl;
//	return 0;
//}

//#include<iostream>
//using namespace std;
//
//typedef int STDataType;
//typedef struct Stack
//{
//	STDataType* a;
//	int top;
//	int capacity;
//}ST;
//
//void STInit(ST& rs, int n = 4)
//{
//	rs.a = (STDataType*)malloc(n * sizeof(STDataType));
//	rs.top = 0;
//	rs.capacity = n;
//}
//
//// 栈顶
//void STPush(ST& rs, STDataType x)
//{
//	// 满了， 扩容
//	if (rs.top == rs.capacity)
//	{
//		printf("扩容\n");
//		int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;
//		STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *
//			sizeof(STDataType));
//		if (tmp == NULL)
//		{
//			perror("realloc fail");
//			return;
//		}
//		rs.a = tmp;
//		rs.capacity = newcapacity;
//	}
//
//	rs.a[rs.top] = x;
//	rs.top++;
//}
//
//int main()
//{
//
//	// 调用全局的
//	ST st1;
//	STInit(st1);
//	STPush(st1, 1);
//	STPush(st1, 2);
//
//	return 0;
//}

//#include <iostream>
//using namespace std;
//
//typedef struct ListNode {
//    int val;
//    struct ListNode* next;
//} LTNode;
//
//// 在链表末尾添加节点的函数
//void ListPushBack(LTNode** phead, int x) {
//    LTNode* newNode = new LTNode;
//    newNode->val = x;
//    newNode->next = NULL;
//    if (*phead == NULL) {
//        // 如果链表为空，新节点就是头节点
//        *phead = newNode;
//    }
//    else {
//        LTNode* cur = *phead;
//        while (cur->next != NULL) {
//            cur = cur->next;
//        }
//        // 将新节点添加到链表末尾
//        cur->next = newNode;
//    }
//}
//int main() {
//    LTNode* plist = NULL;
//    ListPushBack(&plist, 1);
//
//    return 0;
//}

//#include <iostream>
//using namespace std;
//
//typedef struct ListNode {
//    int val;
//    struct ListNode* next;
//} LTNode, * PNode;
//
//// 在链表末尾添加节点的函数
//void ListPushBack(PNode& phead, int x) {
//    PNode newnode = (PNode)malloc(sizeof(LTNode));
//    newnode->val = x;
//    newnode->next = NULL;
//
//    if (phead == NULL) {
//        phead = newnode;
//    }
//    else {
//        PNode cur = phead;
//        while (cur->next != NULL) {
//            cur = cur->next;
//        }
//        cur->next = newnode;
//    }
//}
//
//int main() {
//    PNode plist = NULL;
//    ListPushBack(plist, 1);
//
//    return 0;
//}


//int* STTop(ST& rs)
//{
//	assert(rs.top > 0);
//
//	//return &(rs.a[rs.top - 1]);
//	return rs.a + (rs.top - 1);
//}
//
//int& STTop(ST& rs)
//{
//	assert(rs.top > 0);
//
//	return rs.a[rs.top - 1];
//}

//int* func()
//{
//    int ret = 10;
//    ret++;
//
//    //......
//    return &ret;
//}
//
//int& func1()
//{
//    int ret = 10;
//    ret++;
//
//    //......
//    return ret;
//}


//#include<iostream>
//using namespace std;
//typedef struct SeqList
//{
//	int a[10];
//	int size;
//}SLT;
//// ⼀些主要⽤C代码实现版本数据结构教材中，使⽤C++引⽤替代指针传参，
//// ⽬的是简化程序，避开复杂的指针，但是很多同学没学过引⽤，导致⼀头雾⽔。
//
//void SeqPushBack(SLT & sl, int x)
//{}
//typedef struct ListNode
//{
//	int val;
//	struct ListNode* next;
//}LTNode, * PNode;
//// 指针变量也可以取别名，这⾥LTNode*& phead就是给指针变量取别名
//// 这样就不需要⽤⼆级指针了，相对⽽⾔简化了程序
//
////void ListPushBack(LTNode** phead, int x)
// //void ListPushBack(LTNode*& phead, int x)
//	void ListPushBack(PNode& phead, int x)
//{
//	PNode newnode = (PNode)malloc(sizeof(LTNode));
//	newnode->val = x;
//	newnode->next = NULL;
//	if (phead == NULL)
//	{
//		phead = newnode;
//	}
//	else
//	{
//	}
//}
//
//int main()
//{
//	PNode plist = NULL;
//	ListPushBack(plist, 1);
//	return 0;
//}

//#include<iostream>
//using namespace std;
//int main()
//{
//	// 权限不能放大
//	const int a = 10;
//	const int* p1 = &a;
//	//int* p2 = p1;
//
//	// //权限可以缩小
//	//int b = 20;
//	//int* p3 = &b;
//	//const int* p4 = p3;
//
//	// //不存在权限放大，因为const修饰的是p5本身不是指向的内容
//	//int* const p5 = &b;
//	//int* p6 = p5;
//
//	return 0;
//}


//#include<iostream>
//using namespace std;
//int main()
//{
//	int a = 10;
//	const int& ra = 30;
//	// 编译报错: “初始化” :⽆法从“int”转换为“int& ”
//		// int& rb = a * 3;
//		const int& rb = a * 3;
//	double d = 12.34;
//	// 编译报错：“初始化” :⽆法“double”转换为“int& ”
//		// int& rd = d;
//		const int& rd = d;
//	return 0;
//}

//#include<iostream>
//using namespace std;
//void f1(const T& rx)
//void f1(const int& rx)
//{}
//
//int main()
//{
//	const int xx = 20;
//	int a = 10;
//	const int& rb = a * 3;
//
//	double d = 12.34;
//	const int& rd = d;
//
//	f1(xx);
//	f1(a);
//	f1(a*3);
//	f1(d);
//
//	return 0;
//}




//#include<iostream>
//using namespace std;
//typedef struct SeqList
//{
//	int a[10];
//	int size;
//}SLT;
//// ⼀些主要⽤C代码实现版本数据结构教材中，使⽤C++引⽤替代指针传参，
//// ⽬的是简化程序，避开复杂的指针，但是很多同学没学过引⽤，导致⼀头雾⽔。
//
//void SeqPushBack(SLT& sl, int x)
//{}
//typedef struct ListNode
//{
//	int val;
//	struct ListNode* next;
//}LTNode, * PNode;
//// 指针变量也可以取别名，这⾥LTNode*& phead就是给指针变量取别名
//// 这样就不需要⽤⼆级指针了，相对⽽⾔简化了程序
//
////void ListPushBack(LTNode** phead, int x)
// //void ListPushBack(LTNode*& phead, int x)
//void ListPushBack(PNode& phead, int x)
//{
//	PNode newnode = (PNode)malloc(sizeof(LTNode));
//	newnode->val = x;
//	newnode->next = NULL;
//	if (phead == NULL)
//	{
//		phead = newnode;
//	}
//	else
//	{
//	}
//}
//
//int main()
//{
//	PNode plist = NULL;
//	ListPushBack(plist, 1);
//	return 0;
//}

//#include<iostream>
//using namespace std;
//int main()
//{
//	int a = 10;
//	const int& ra = 30;
//	// 编译报错: “初始化” :⽆法从“int”转换为“int& ”
//		// int& rb = a * 3;
//	const int& rb = a * 3;
//	double d = 12.34;
//	// 编译报错：“初始化” :⽆法“double”转换为“int& ”
//		// int& rd = d;
//	const int& rd = d;
//	return 0;
//}


//
//#include<iostream>
//using namespace std;
//void f1(const int& rx)
//{
//    // 在这里，我们在函数接收引用类型的形参时，为了确保不会通过这个形参去改变传入的实参，
//    // 所以在形参前面加上了 `const` 进行修饰。
//}
//
//int main()
//{
//    // 定义一个常量 `xx`，其值为 `20`
//    const int xx = 20;
//
//    // 定义一个普通整型变量 `a`，初始值为 `10`
//    int a = 10;
//
//    // 下面这行代码如果写成这样：`int& rb = a * 3;` 是存在问题的。
//    // 因为这里引用的是 `a * 3` 这个表达式的整体，而表达式的结果会用一个临时对象进行存储。
//    // 按照C++的规定，临时对象具有常性，就好像已经被 `const` 修饰过一样。
//    // 所以如果直接用普通引用去引用这个临时对象，就相当于触发了权限放大的情况，这是不允许的。
//    // 正确的做法是像下面这样，在引用前面加上 `const`，使其成为常引用。
//    const int& rb = a * 3;
//
//    // 这里的 `rb` 引用的就是那个临时对象，也就是 `a * 3` 的结果存储在了这个临时变量里面。
//
//    // 再看下面的情况，定义一个双精度浮点数 `d`，值为 `12.34`
//    double d = 12.34;
//
//    // 如果直接写成 `int &rd = d;` 是不行的。
//    // 因为我们不能用 `int` 类型的数据去引用其他类型的数据。
//    // 当进行这种不同类型之间的转换时，中间会生成临时变量，
//    // 并且这个临时对象同样具有常性，就如同已经被 `const` 修饰了一样。
//    // 所以这里也触发了权限放大的情况，那么左边同样也要进行 `const` 修饰的操作，
//    // 正确的写法如下：
//    const int& rd = d;
//
//    // 接下来进行函数调用
//    f1(xx);  // 可以将常量对象 `xx` 传递给函数 `f1`
//    f1(a);   // 也可以将普通值 `a` 传递给函数 `f1`
//    f1(a * 3);  // 还可以将表达式 `a * 3` 的结果（也就是对应的临时对象）传递给函数 `f1`
//    f1(d);   // 同样可以将带有类型转换的 `d`（实际传递的是转换过程中生成的临时对象）传递给函数 `f1`
//
//    // 如果采用 `const` 引用进行传参的话，其适用范围是比较宽泛的，可以接收多种类型的对象，
//    // 包括普通对象、临时对象以及 `const` 对象等。
//
//    return 0;
//}

//#include<iostream>
//using namespace std;
//int main()
//{
//    // 首先定义一个常量a，并初始化为10，由于它被声明为const，所以其值是不能被修改的。
//    const int a = 10;
//
//    // 接着定义一个指针p1，它指向常量a。这里的指针类型是const int*，意味着通过这个指针不能修改它所指向的数据。
//    const int* p1 = &a;
//
//    // 如果像下面这样写是错误的，因为这属于权限的放大。这里试图将指向常量的指针p1赋值给一个普通指针p2，
//    // 普通指针p2是可以用来修改它所指向的数据的，而p1指向的是常量a，不应该通过这种赋值来获得可修改的权限。
//    // int* p2 = p1;
//
//    /*
//    当我们像上面那样定义了指针p1指向常量a后，就意味着p1已经被固定指向a了，
//    我们就不能再去修改它的指向了。这是因为我们在定义p1时，在指针类型中通过const进行了限制，
//    具体来说，当const在*右边时，就表明这个指针所指向的变量已经被限制，不能随意改变其指向了。
//
//    而当const在*左边时，比如const int*这种形式，就意味着我们不能通过这个指针对它所指向的数据进行修改操作。
//    */
//
//    // 再定义一个普通整型变量b，并初始化为20。
//    int b = 20;
//
//    // 然后定义一个指针p3，它指向变量b，也就是说p3存储的是b的地址，通过这个指针p3是可以对b进行修改操作的。
//    int* p3 = &b;
//
//    // 接着定义一个指针p4，它同样指向变量b，不过这里的指针类型是const int*，这就使得我们通过p4只能对b进行读取操作，而不能进行修改操作。
//    const int* p4 = p3;
//
//
//    // 下面这种情况，定义了一个指针p4，这里的const在*右边，它的完整声明是int* const p4 = &b;，
//    // 这表示一旦p4被初始化指向b后，就不能再修改它的指向了，它会一直指向这个初始设定的数。
//    int* const p4 = &b;
//
//    // 然后将p4赋值给p5是可以的，因为p5是一个普通指针，它可以接收p4的值（也就是b的地址），并且可以通过它来对b进行操作（前提是符合相应的权限规则）。
//    int* p5 = p4;
//
//
//    return 0;
//}



//#include <iostream>
//
//// 实现⼀个ADD宏函数的常⻅问题
//
//// 以下是几种错误的宏定义方式示例
//// #define ADD(int a, int b) return a + b;  // 这种定义方式是错误的，语法上不符合宏定义的要求
//// #define ADD(a, b) a + b;  // 这样简单的定义可能会导致优先级等问题
//// #define ADD(a, b) (a + b)  // 虽然加了括号，但还不够完善，可能在复杂表达式中出现问题
//
//// 正确的宏实现
//#define ADD(a, b) ((a) + (b))
//// 为什么不能加分号?宏是替换机制的 ，在宏定义后面加分号的话就有问题了。
//// 例如，如果宏定义后面带分号，在代码中使用该宏时替换过去可能会导致多余的分号出现在不该出现的位置，引发语法错误。
//
//// 为什么要加外⾯的括号? 不加外面的括号这个优先级就有问题了。
//// 比如在一些复杂运算场景下，如与其他运算符组合使用时，如果没有外面的括号明确整体运算顺序，
//// 可能会先执行其他运算再执行加法，导致结果不符合预期。
//
//// 为什么要加⾥⾯的括号? 同样是为了保持优先级。
//// 当宏中的变量参与其他运算后再进行加法运算时，里面的括号能确保每个变量先完成自身相关运算后再相加，
//// 避免因优先级混乱而得出错误结果。
//
//int main() {
//    // 使用ADD宏计算1和2的和，并将结果存储在ret中
//    int ret = ADD(1, 2); // 宏是替换机制的，这里会将ADD(1, 2)替换为((1) + (2))
//    std::cout << ret << std::endl;
//
//    // 第一个问题相关的调用，单纯输出1和2通过宏计算后的结果
//    std::cout << ADD(1, 2) << std::endl;
//
//    // 第二个问题相关的调用，先通过宏计算1和2的和，然后再乘以5
//    // 这里能体现出括号对于保证优先级的重要性，如果宏定义的括号不正确，可能会导致计算顺序错误
//    std::cout << ADD(1, 2) * 5 << std::endl;
//
//    int x = 1, y = 2;
//    // 第三个问题相关的调用，将x和y进行按位与、按位或运算后再通过宏进行加法运算
//    // 实际替换后就变成了 (x&y + x|y)，这里也能看出宏定义中括号的作用，确保运算顺序正确
//    ADD(x & y, x | y);
//
//    return 0;
//}

/*
宏函数缺点很多，比如可读性差、调试困难等，但是它基于替换机制，调用时不用建立栈帧，能提高效率，开销小。

大概就是因为宏函数存在这些优缺点吧，我们的祖师爷觉得不太能忍受它的一些不足，于是就创建了这个inline关键字来解决一些相关的问题啦。
*/


//
//#include <iostream>
//
//// 定义一个内联函数，用于计算两个整数的和
//inline int add(int a, int b) {
//    return a + b;
//}
//
//int main() {
//    int num1 = 5;
//    int num2 = 3;
//
//    // 调用内联函数add
//    int result = add(num1, num2);
//
//    std::cout << "两数之和为: " << result << std::endl;
//
//    return 0;
//}

//#include<iostream>
//using namespace std;
//void func(int x)
//{
//	cout << "func1" << endl;
//}
//
//void func(int* x)
//{
//	cout << "func1" << endl;
//}
//
//int main()
//{
//	func(NULL);
//	func(0);
//	return 0;
//}

#include<iostream>
using namespace std;
void f(int x)
{
    cout << "f(int x)" << endl;
}

void f(int* ptr)
{
    cout << "f(int* ptr)" << endl;
}

int main()
{
    // 如果我们像这样写 `f(0);`，那么就会调用第一个函数 `f(int x)`，因为这里传入的是一个整型常量 `0`，它与第一个函数的整型参数类型匹配。

    // 要是写成 `f(NULL);`，在C语言风格下，这可能会调用第二个函数 `f(int* ptr)`，但在C++中，这样使用 `NULL` 来表示空指针存在类型转换的问题哦。

    // 而在C++中，我们更推荐使用 `nullptr` 来定义空指针，就像下面这样写 `f(nullptr);`，这样可以有效避免类型转换的问题，并且它会准确地调用第二个函数 `f(int* ptr)`，因为 `nullptr` 可以明确地表示一个空指针类型，与第二个函数接受的整型指针参数类型相匹配。

    f(nullptr);

    return 0;
}